<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Custom widget in Ruby GTK</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Custom widget, Ruby, GTK, tutorial, programming, Linux">
<meta name="description" content="In this part of the Ruby GTK tutorial, we create a
custom widget.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Custom widget</h1>


<p>
Most toolkits usually provide only the most common widgets like buttons, text widgets, 
sliders etc. No toolkit can provide all possible widgets. Programmers must create such 
widgets by themselves. They do it by using the drawing tools provided by the toolkit. 
There are two possibilities. A programmer can modify or enhance an existing widget. Or 
he can create a custom widget from scratch.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<h2>Burning widget</h2>

<p>
This is an example of a widget, that we create from scratch. This 
widget can be found in various media burning applications, 
like Nero Burning ROM.
</p>

<div class="codehead">custom.rb</div>
<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial 
#
# This example creates a burning
# custom widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: June 2009


require 'gtk2'

class Burning &lt; Gtk::DrawingArea

    def initialize(parent)
        @parent = parent

        super()
 
        @num = [ "75", "150", "225", "300", 
            "375", "450", "525", "600", "675" ]
 
        set_size_request 1, 30
        signal_connect "expose-event" do
            expose
        end
    end
    

    def expose
    
        cr = window.create_cairo_context
        draw_widget cr
  
    end
    
    def draw_widget cr
 
         cr.set_line_width 0.8

        cr.select_font_face("Courier", 
            Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL)
        cr.set_font_size 11

        width = allocation.width
     
        @cur_width = @parent.get_cur_value

        step = (width / 10.0).round

        till = (width / 750.0) * @cur_width
        full = (width / 750.0) * 700

        if @cur_width >= 700
            
            cr.set_source_rgb(1.0, 1.0, 0.72)
            cr.rectangle(0, 0, full, 30)
            cr.clip
            cr.paint
            cr.reset_clip
            
            cr.set_source_rgb(1.0, 0.68, 0.68)
            cr.rectangle(full, 0, till-full, 30)
            cr.clip
            cr.paint
            cr.reset_clip

        else
            cr.set_source_rgb 1.0, 1.0, 0.72
            cr.rectangle 0, 0, till, 30
            cr.clip
            cr.paint
            cr.reset_clip
        end
       

        cr.set_source_rgb(0.35, 0.31, 0.24)
        
        for i in (1..@num.length)
            cr.move_to i*step, 0
            cr.line_to i*step, 5
            cr.stroke
            
            te = cr.text_extents @num[i-1]
            cr.move_to i*step-te.width/2, 15
            cr.text_path @num[i-1]
            cr.stroke
        end         
    end
end
        
 
class RubyApp &lt; Gtk::Window
    def initialize
        super
    
        set_title "Burning"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end

        set_size_request 350, 200        
        set_window_position Gtk::Window::POS_CENTER
        
        @cur_value = 0
       
        vbox = Gtk::VBox.new false, 2
        
        scale = Gtk::HScale.new
        scale.set_range 0, 750
        scale.set_digits 0
        scale.set_size_request 160, 35
        scale.set_value @cur_value
        
        scale.signal_connect "value-changed" do |w|
            on_changed(w)
        end
                
        fix = Gtk::Fixed.new
        fix.put scale, 50, 50
        
        vbox.pack_start fix
        
        @burning = Burning.new(self)
        vbox.pack_start @burning, false, false, 0

        add vbox
        show_all
    end    
        
    def on_changed widget
    
        @cur_value = widget.value
        @burning.queue_draw
    end
    
    def get_cur_value
        return @cur_value
    end
end
    
Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
We put a <code>DrawingArea</code> on the bottom of the window and draw the 
entire widget manually. All the important code resides in the <code>draw_widget</code> 
which is called from the <code>expose</code> method of the Burning class. 
This widget shows graphically the total capacity of a medium and the free space available to us. 
The widget is controlled by a scale widget. The minimum value of our custom widget is 0, the 
maximum is 750. If we reach value 700, we began drawing in red colour. This normally indicates 
overburning.  
</p>

<pre class="explanation">
@num = [ "75", "150", "225", "300", 
    "375", "450", "525", "600", "675" ]
</pre>

<p>
These numbers are shown on the burning widget. They show the capacity of the medium.
</p>

<pre class="explanation">
@cur_width = @parent.get_cur_value
</pre>

<p>
From the parent widget, we get the current value of the scale widget.
</p>

<pre class="explanation">
till = (width / 750.0) * @cur_width
full = (width / 750.0) * 700
</pre>

<p>
We use the <code>width</code> variable to do the transformations. Between 
the values of the scale and the custom widget's measures. Note that we use floating
point values. We get greater precision in drawing.
The <code>till</code> parameter determines the total size to be drawn. 
This value comes from the slider widget. It is a proportion of the whole area. 
The <code>full</code> parameter determines the point,
where we begin to draw in red color. 
</p>

<pre class="explanation">
cr.set_source_rgb(1.0, 1.0, 0.72)
cr.rectangle(0, 0, full, 30)
cr.clip
cr.paint
cr.reset_clip
</pre>

<p>
We draw a yellow rectangle up to point, where the medium is full.
</p>

<pre class="explanation">
te = cr.text_extents @num[i-1]
cr.move_to i*step-te.width/2, 15
cr.text_path @num[i-1]
cr.stroke
</pre>

<p>
This code here draws the numbers on the burning widget. We calculate the
text extents to position the text correctly.
</p>

<pre class="explanation">
def on_changed widget

    @cur_value = widget.value
    @burning.queue_draw
end
</pre>

<p>
We get the value from the scale widget, store it in the <code>@cur_value</code> variable 
for later use. We redraw the burning widget. 
</p>

<img src="/img/gui/rubygtk/burning.png" alt="Burning widget">
<div class="figure">Figure: Burning widget</div>

<p>
In this chapter, we created a custom widget in GTK and Ruby programming language.
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified June 28, 2009  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

